﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace BaseUi.Api
{
    public static class ApiHelp
    {
        public static HttpClient httpClient;
        static ApiHelp()
        {
            httpClient = new HttpClient();
            httpClient.Timeout = TimeSpan.FromSeconds(5);
            httpClient.DefaultRequestHeaders.Add("User-Agent", "Chrome/95.0.4638.69 Safari/537.36");
            //ServicePointManager.Expect100Continue = false;
        }

        /// <summary>
        /// GET请求
        /// </summary>
        /// <typeparam name="T">类型。可以为string和对象</typeparam>
        /// <param name="uri">地址</param>
        /// <param name="query">请求头。URI中的查询信息</param>
        /// <param name="body">请求体。转为json字符串形式</param>
        /// <returns>成功返回对象，成功但StatusCode不在200-299返回默认值</returns>
        public static T Get<T>(string uri, object? query = null, object? body = null)
        {
            return Send<T>(HttpMethod.Get, uri, query, body);
        }

        /// <summary>
        /// GET请求
        /// </summary>
        /// <typeparam name="T">类型。可以为string和对象</typeparam>
        /// <param name="uri">多个地址。如["https://0.0.0.1","/User/Login"]</param>
        /// <param name="query">请求头。URI中的查询信息</param>
        /// <param name="body">请求体。转为json字符串形式</param>
        /// <returns>成功返回对象，成功但StatusCode不在200-299返回默认值</returns>
        public static T Get<T>(IEnumerable<object> uri, object? query = null, object? body = null)
        {
            return Send<T>(HttpMethod.Get, uri, query, body);
        }

        /// <summary>
        /// POST请求
        /// </summary>
        /// <typeparam name="T">类型。可以为string和对象</typeparam>
        /// <param name="uri">地址</param>
        /// <param name="query">请求头。URI中的查询信息</param>
        /// <param name="body">请求体。转为json字符串形式</param>
        /// <returns>成功返回对象，成功但StatusCode不在200-299返回默认值</returns>
        public static T Post<T>(string uri, object? body = null, object? query = null)
        {
            return Send<T>(HttpMethod.Post, uri, query, body);
        }

        /// <summary>
        /// POST请求
        /// </summary>
        /// <typeparam name="T">类型。可以为string和对象</typeparam>
        /// <param name="uri">多个地址。如["https://0.0.0.1","/User/Login"]</param>
        /// <param name="query">请求头。URI中的查询信息</param>
        /// <param name="body">请求体。转为json字符串形式</param>
        /// <returns>成功返回对象，成功但StatusCode不在200-299返回默认值</returns>
        public static T Post<T>(IEnumerable<object> uri, object? body = null, object? query = null)
        {
            return Send<T>(HttpMethod.Post, uri, query, body);
        }

        /// <summary>
        /// 发送请求
        /// </summary>
        /// <typeparam name="T">类型。可以为string和对象</typeparam>
        /// <param name="uri">地址</param>
        /// <param name="query">请求头。URI中的查询信息</param>
        /// <param name="body">请求体。转为json字符串形式</param>
        /// <returns>成功返回对象，成功但StatusCode不在200-299返回默认值</returns>
        public static T Send<T>(HttpMethod method, string uri, object? query = null, object? body = null)
        {
            return Send<T>(method, new string[] { uri }, query, body);
        }

        /// <summary>
        /// 发送请求
        /// </summary>
        /// <typeparam name="T">类型。可以为string和对象</typeparam>
        /// <param name="uri">多个地址。如["https://0.0.0.1","/User/Login"]</param>
        /// <param name="query">请求头。URI中的查询信息</param>
        /// <param name="body">请求体。转为json字符串形式</param>
        /// <returns>成功返回对象，成功但StatusCode不在200-299返回默认值</returns>
        public static T Send<T>(HttpMethod method, IEnumerable<object> uri, object? query = null, object? body = null)
        {
            HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, "".AppendPathSegments(uri).SetQueryParams(query));

            if (body != null)
            {
                var content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json");
                httpRequestMessage.Content = content;
            }

            var re = httpClient.SendAsync(httpRequestMessage).Result;
            if (!re.IsSuccessStatusCode)
                return default(T)!;

            var con = re.Content.ReadAsStringAsync().Result;

            var tType = typeof(T);
            if (tType == typeof(string))
                return (T)(object)con;

            return JsonConvert.DeserializeObject<T>(con)!;
        }

        /// <summary>
        /// 追加路径片段（有更高要求可以使用Flurl库）
        /// </summary>
        /// <param name="url">地址，如 https://www.baidu.com</param>
        /// <param name="segments">路径片段</param>
        /// <returns>地址</returns>
        public static string AppendPathSegments(this string url, IEnumerable<object> segments)
        {
            string urlStr = url.Trim();
            foreach (var segment in segments)
            {
                var val = segment?.ToString()?.Trim() ?? "";
                if (string.IsNullOrWhiteSpace(val))
                    continue;

                if (urlStr.EndsWith("/"))
                    urlStr = urlStr.Substring(0, urlStr.Length - 1);

                if (val.Length > 0)
                    urlStr += string.IsNullOrEmpty(urlStr) || val.StartsWith("/") ? val : $"/{val}";
            }
            return urlStr;
        }

        /// <summary>
        /// 设置Query参数（有更高要求可以使用Flurl库）
        /// </summary>
        /// <param name="url">地址，如 https://www.baidu.com/s</param>
        /// <param name="values">参数，支持字典和对象</param>
        /// <returns>地址</returns>
        public static string SetQueryParams(this string url, object? values)
        {
            string urlStr = url;
            if (values == null)
                return urlStr;

            List<string> kv = new List<string>();
            if (values is IEnumerable jh)
            {
                if (jh is IDictionary dict)
                {
                    foreach (DictionaryEntry item in dict)
                        kv.Add($"{item.Key?.ToString()}={item.Value?.ToString()}");
                }
            }
            else
            {
                foreach (var item in values.GetType().GetProperties())
                {
                    if (item.CanRead)
                        kv.Add($"{item.Name}={item.GetValue(values)?.ToString()}");
                }
            }

            if (kv.Any())
            {
                if (!urlStr.Contains("?"))
                    urlStr += "?";
                else
                {
                    if (!urlStr.EndsWith("&"))
                        urlStr += "&";
                }

                urlStr += string.Join("&", kv);
            }

            return urlStr;
        }
    }
}
